package com.papper.common.utils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ClassUtil
 * <h5>描述:</h5>
 */
public class ClassUtil {
	private static final String                PROXY_PREFIX = "com.sun.proxy";
	private static final Map<String, Class<?>> CACHE        = new ConcurrentHashMap<>(16);

	/**
	 * 返回定义类时的泛型参数的类型. <br>
	 * 如:定义一个BookManager类<br>
	 * <code>{@literal public BookManager extends GenricManager<Book,Address>}{...} </code>
	 * <br>
	 * 调用getSuperClassGenricType(getClass(),0)将返回Book的Class类型<br>
	 * 调用getSuperClassGenricType(getClass(),1)将返回Address的Class类型
	 *
	 * @param clazz 从哪个类中获取
	 * @param index 泛型参数索引,从0开始
	 * @return 返回泛型类型class
	 * @throws IndexOutOfBoundsException
	 */
	public static Class<?> getSuperClassGenricType(Class<?> clazz, int index) throws IndexOutOfBoundsException {
		Type genType = clazz.getGenericSuperclass();
		if (!(genType instanceof ParameterizedType)) {
			return Object.class;
		}
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		if (index >= params.length || index < 0) {
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			return Object.class;
		}
		return (Class<?>) params[index];
	}

	/**
	 * 返回接口类的泛型参数的类型
	 *
	 * @param clazz 从哪个类中获取
	 * @param index 泛型参数索引,从0开始
	 * @return 返回class对象
	 */
	public static Class<?> getSuperInterfaceGenericType(Class<?> clazz, int index) {
		String key = clazz.getName() + index;
		return CACHE.computeIfAbsent(key, k -> doGetSuperInterfaceGenericType(clazz, index));
	}

	private static Class<?> doGetSuperInterfaceGenericType(Class<?> clazz, int index) {
		String name = clazz.getName();
		if (name.startsWith(PROXY_PREFIX)) {
			Type[] interfacesTypes = clazz.getGenericInterfaces();
			if (interfacesTypes.length == 0) {
				return Object.class;
			}
			clazz = (Class<?>) interfacesTypes[0];
			return doGetSuperInterfaceGenericType(clazz, index);
		}
		Type[] interfacesTypes = clazz.getGenericInterfaces();
		if (interfacesTypes.length == 0) {
			return Object.class;
		}
		Type   firstInterface = interfacesTypes[0];
		Type[] params         = ((ParameterizedType) firstInterface).getActualTypeArguments();
		if (index >= params.length || index < 0) {
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			return Object.class;
		}
		return (Class<?>) params[index];
	}

	/**
	 * 返回类名并且第一个字母小写
	 *
	 * @param clazz class类型
	 * @return 返回类名并且第一个字母小写
	 */
	public static String getClassSimpleName(Class<?> clazz) {
		String className = clazz.getSimpleName();
		return className.substring(0, 1).toLowerCase() + className.substring(1);
	}

	/**
	 * 将实体对象转换成Map。已废弃，使用MyBeanUtil.pojoToMap(pojo)
	 *
	 * @param pojo 实体类
	 * @return 返回map
	 * @deprecated 使用MyBeanUtil.pojoToMap(pojo)
	 */
	@Deprecated
	public static Map<String, Object> pojoToMap(Object pojo) {
		return MyBeanUtil.pojoToMap(pojo);
	}

	/**
	 * map集合转换成对象集合。已废弃，使用MyBeanUtil.mapListToObjList(list, pojoClass);
	 *
	 * @param list      map集合
	 * @param pojoClass 待转换的对象类型
	 * @param <T>       实体类
	 * @return 返回对象集合
	 * @deprecated 使用MyBeanUtil.mapListToObjList(list, pojoClass);
	 */
	@Deprecated
	public static <T> List<T> mapListToObjList(List<Map<String, Object>> list, Class<T> pojoClass) {
		return MyBeanUtil.mapListToObjList(list, pojoClass);
	}

	/**
	 * 将map对象转换成普通类。已废弃，使用MyBeanUtil.mapToPojo(map, pojoClass);
	 *
	 * @param map       map对象
	 * @param pojoClass 普通类
	 * @param <T>       实体类
	 * @return 返回普通类
	 * @deprecated 使用MyBeanUtil.mapToPojo(map, pojoClass);
	 */
	@Deprecated
	public static <T> T mapToPojo(Map<String, Object> map, Class<T> pojoClass) {
		return MyBeanUtil.mapToPojo(map, pojoClass);
	}

	/**
	 * 是否是数组或结合类
	 *
	 * @param value 待检测对象
	 * @return true，是结合或数组
	 */
	public static boolean isArrayOrCollection(Object value) {
		boolean ret = false;
		if (value.getClass().isArray()) {
			ret = true;
		} else if (value instanceof Collection) {
			ret = true;
		}
		return ret;
	}

	/**
	 * Check if it is the basic data type of json data
	 *
	 * @param type0 java class name
	 * @return boolean
	 */
	public static boolean isPrimitive(String type0) {
		if (Objects.isNull(type0)) {
			return true;
		}
		String type = type0.contains("java.lang") ? type0.substring(type0.lastIndexOf(".") + 1, type0.length()) : type0;
		type = type.toLowerCase();
		switch (type) {
			case "string":
			case "integer":
			case "int":
			case "object":
			case "void":
			case "long":
			case "double":
			case "float":
			case "short":
			case "bigdecimal":
			case "char":
			case "character":
			case "number":
			case "boolean":
			case "byte":
			case "uuid":
			case "java.sql.timestamp":
			case "java.util.date":
			case "java.time.localdatetime":
			case "java.time.localtime":
			case "date":
			case "localdatetime":
			case "localdate":
			case "zoneddatetime":
			case "java.time.localdate":
			case "java.time.zoneddatetime":
			case "java.math.bigdecimal":
			case "java.math.biginteger":
			case "java.util.uuid":
			case "java.util.UUID":
			case "java.io.serializable":
				return true;
			default:
				return false;
		}
	}
}
